package root;

import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

import root.user.UserManager;

import exceptions.InvalidLogin;
import exceptions.InvalidSession;
import exceptions.SessionDoesNotExist;
import exceptions.UserNotExistsException;

public class SessionManager {
	
	private Map<String, Session> map;
	private static SessionManager sessionManager;
	
	/**
	 * Padrao SingleTon, retorna a unica instancia da classe
	 * @return
	 */
	public static SessionManager getSessionManager() {
		if (sessionManager == null)
			sessionManager = new SessionManager();
		return sessionManager;
	}
	
	private SessionManager() {
		map = new TreeMap<String, Session>();
	}
	
	private String getNewAvaibleSession() {
		String returnValue = "";
		Random rand = new Random();
		try {
			do{
				returnValue = Long.toString(rand.nextLong()) + Long.toBinaryString(rand.nextLong()); 
			} while (hasSession(returnValue));
		} catch (InvalidSession e) {
			e.printStackTrace();
		}
		return returnValue;
	}
	
	/**
	 * Cria uma sessao a partir de um username
	 * @param username
	 * 	Username que vai ter a sessao criada
	 * @return
	 * 	ID da sessao
	 * @throws InvalidLogin
	 * @throws UserNotExistsException 
	 */
	public String createSession(String username) throws InvalidLogin, UserNotExistsException {
		if (username == null || username.equals("")) {
			throw new InvalidLogin();
		}
		if(!UserManager.getUserManager().hasUser(username)){
			throw new UserNotExistsException("Usuário inexistente");
		}
			
		String returnValue = getNewAvaibleSession();
		map.put( returnValue , new Session(username) );
		return returnValue;
	}
	
	private boolean isValidSession(String id) {
		if (id == null || id.isEmpty()) {
			return false;
		}
		return true;
	}

	/**
	 * Pega  a secao pelo id
	 * @param id
	 * @return
	 * 	Sessao
	 * @throws SessionDoesNotExist
	 * 	Se nao existir sessao correspondente aquele id
	 * @throws InvalidSession 
	 */
	public Session getSession(String id) throws SessionDoesNotExist, InvalidSession {
		if (!isValidSession(id))
			throw new InvalidSession("Sessão inválida");
		if (!hasSession(id)) {
			throw new SessionDoesNotExist("Sessão inexistente");
		}
		return map.get(id);
	}
	

	/**
	 * Verifica se a sessao com ID existe 
	 * @param id
	 * @return
	 * 	True se existir.
	 */
	public boolean hasSession(String id) throws InvalidSession {
		if (!isValidSession(id))
			throw new InvalidSession("Sessão inválida");
		return map.containsKey(id);
	}
	
	/**
	 * Mata uma sessao
	 * @param id
	 * @throws SessionDoesNotExist
	 * @throws InvalidSession 
	 */
	public void killSession(String id) throws SessionDoesNotExist, InvalidSession {
		if (!hasSession(id)) {
			throw new SessionDoesNotExist("Sessão inexistente");
		}
		map.remove(id);
	}

	/**
	 * Seta determina instancia
	 * @param ssM
	 * 	Instancia  a ser setada.
	 */
	public static void setInstance(SessionManager ssM) {
		sessionManager = ssM;
	}
}
